package com.wl.dzt.sys.core.dao.curd.mysql;

import com.wl.dzt.sys.core.dao.DB;
import com.wl.dzt.sys.core.dao.curd.CrudCommand;
import com.wl.dzt.sys.core.dao.curd.CrudConvert;
import com.wl.dzt.sys.core.dao.curd.CrudConvertResult;
import com.wl.dzt.sys.core.dao.curd.sql.SqlSearchResult;
import com.wl.dzt.sys.core.dao.curd.sql.el.SqlParam;
import com.wl.dzt.sys.core.dao.curd.sql.el.SqlParamBuilder;
import com.wl.dzt.sys.core.dao.select.Select;
import com.wl.dzt.sys.core.dao.select.mapper.DataMapper;
import com.wl.dzt.sys.util.LogicUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;


/**
 * @author wl_code@163.com
 * @date 2018/7/5/005
 * @version 1.0
 * @description mysql增删改查命令
 * 
 */
@Component("mysql")
public class CrudCommandForMysql implements CrudCommand {

    private static final Logger log = LoggerFactory.getLogger(CrudCommandForMysql.class);

    /**
     * jdbcTemplate
     */
    @Resource
    protected JdbcTemplate jdbcTemplate;

    /**
     * 默认数据适配器
     */
    protected DataMapper dataMapper = new DataMapper() {
    };

    /**
     * mysql转换器
     */
    @Resource
    private CrudConvert crudConvertForMysql;

    /**
     * <b>新增</b>
     * <p>
     * 添加一个数据
     * </p>
     *
     * @param entity
     * @return
     */
    public boolean insert(Object entity) {
        return excute(crudConvertForMysql.insertConvert(entity), entity);
    }

    /**
     * <b>修改</b>
     * <p>
     * 修改一个数据
     * </p>
     *
     * @param entity
     * @return
     */
    public boolean update(Object entity) {
        return DB.idOtherFields(entity) ? true : excute(crudConvertForMysql.updateConvert(entity), entity);
    }

    /**
     * <b>删除</b>
     * <p>
     * 根据ID删除一个数据
     * </p>
     *
     * @param clazz
     * @param id
     * @return
     */
    public boolean delete(Class<?> clazz, String id) {
        CrudConvertResult result = crudConvertForMysql.deleteConvert(clazz, id);
        log.debug("delete:{}", result.getSql());
        log.debug("deleteArgs:{}", id);
        return this.jdbcTemplate.update(result.getSql(), result.getArgs()) > 0;
    }

    /**
     * <b>查询</b>
     * <p>
     * 根据查询条件查询数据
     * </p>
     *
     * @param select
     * @return
     */
    public List<?> select(Select select) {
        return getObjects(select, crudConvertForMysql);
    }

    public List<?> getObjects(Select select, CrudConvert crudConvertForMysql) {
        CrudConvertResult result = crudConvertForMysql.selectConvert(select);
        log.debug("query:{}", result.getSql());
        log.debug("queryArgs:{}", Arrays.toString(result.getArgs()));
        List<Map<String, Object>> data = jdbcTemplate.queryForList(result.getSql(), result.getArgs());
        List rows = new ArrayList();
        data.forEach(row -> {
            try {
                rows.add(dataMapper.mapper(select.getClazz(), row));
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        });
        return rows;
    }

    /**
     * 获取jdbcTemplate
     */
    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    /**
     * <b>不适配实体查询</b>
     * <p>
     * 直接返回map对象而并不将其转换为实体
     * </p>
     *
     * @param select
     * @return
     */
    public List<Map<String, Object>> selectByMap(Select select) {
        return getMaps(select, crudConvertForMysql, log);
    }

    public  List<Map<String, Object>> getMaps(Select select, CrudConvert crudConvertForMysql, Logger log) {
        CrudConvertResult result = crudConvertForMysql.selectConvert(select);
        log.debug("query:{}", result.getSql());
        log.debug("queryArgs:{}", Arrays.toString(result.getArgs()));
        List<Map<String, Object>> data = jdbcTemplate.queryForList(result.getSql(), result.getArgs()), list = new ArrayList<>();
        data.forEach(row -> {
            Map<String, Object> map = new HashMap<>();
            row.forEach((k, v) -> map.put(k.replaceAll("_", "."), v));
            list.add(map);
        });
        return list;
    }

    /**
     * <b>总数</b>
     * <p>
     * 根据查询条件查询总数
     * </p>
     *
     * @param select
     * @return
     */
    public Integer count(Select select) {
        return countMethod(select, crudConvertForMysql);
    }

    public Integer countMethod(Select select, CrudConvert crudConvertForMysql) {
        CrudConvertResult result = crudConvertForMysql.countConvert(select);
        log.debug("query:{}", result.getSql());
        log.debug("queryArgs:{}", Arrays.toString(result.getArgs()));
        List<Map<String, Object>> data = jdbcTemplate.queryForList(result.getSql(), result.getArgs());
        return Integer.valueOf(data.get(0).get("c").toString());
    }

    /**
     * <b>执行</b>
     * <p>
     * 执行修改或者删除
     * </p>
     *
     * @param entity
     * @return
     */
    public boolean excute(CrudConvertResult result, Object entity) {
        boolean exitId = DB.exitId(entity);
        log.debug(String.format((exitId ? "update:%s" : "insert:%s"), result.getSql()));
        log.debug(String.format((exitId ? "updateArgs:%s" : "insertArgs:%s"), Arrays.toString(result.getArgs())));
        // 存在ID并且参数有一个则无修改字段直接成功
        if (result.getArgs().length == 1 && exitId) {
            return true;
        }
        // 一个参数都没有无需修改或者添加直接成功
        if (result.getArgs().length == 0) {
            return true;
        }
        if (this.jdbcTemplate.update(result.getSql(), result.getArgs()) > 0) {
            DB.setId(entity, result.getId());
            return true;
        }
        return false;
    }

    /**
     * <b>改变JdbcTemplate</b>
     * <p>
     * 切换JdbcTemplate
     * </p>
     *
     * @param jdbcTemplate
     */
    public void changeJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * <b>改变JdbcTemplate</b>
     * <p>
     * 切换数据库编译器
     * </p>
     *
     * @param convert
     */
    public void changeCrudConvert(CrudConvert convert) {
        this.crudConvertForMysql = convert;
    }

    /**
     * <b>sql表达式查询</b>
     * <p>
     * 根据特殊的sql表达式子查询数据
     * </p>
     *
     * @param select
     * @return
     */
    public SqlSearchResult selectBySqlExp(Select select) {
        SqlSearchResult sqlSearchResult = new SqlSearchResult();
        try {
            // 查询数据
            SqlParamBuilder sqlParamBuilder = new SqlParamBuilder(select.getSqlExp());
            SqlParam sqlParam = sqlParamBuilder.create(select.getWheres(), select.getStart(), select.getLimit());
            String sql = (select.getLimit() == 0 && select.getStart() == 0) ? sqlParam.getFullSql() : String.format(
                    crudConvertForMysql.getPageTemplate(), sqlParam.getFullSql(), select.getStart(), select.getLimit());
            log.debug("query:{}", sql);
            List<Map<String, Object>> data = jdbcTemplate.queryForList(sql), list = new ArrayList<>();
            data.forEach(row -> {
                Map<String, Object> map = new HashMap<>();
                row.forEach((k, v) -> map.put(k.replaceAll("_", "."), v));
                list.add(map);
            });
            sqlSearchResult.setData(data);
            // 查询总数
            Map<String, Object> result = jdbcTemplate.queryForMap(sqlParam.countSql());
            log.debug("query:{}", sqlParam.countSql());
            if (result != null) {
                Object longStr = LogicUtil.empty(result.get("count")) ? result.get("COUNT") : result.get("count");
                Integer count = new Integer(longStr.toString());
                sqlSearchResult.setCount(count);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sqlSearchResult;
    }

}
